﻿import pao = require('../public');
import express = require('express');
import http = require('http');
import fs = require("fs");
import path = require('path');

/**
 * 全局服务列表
 */
export class globalServices {

};

const moduleName = "pao.server";
/**
 * 服务信息: 包含服务名称和服务对象的信息
 */
@pao.addon("服务信息",
    "包含服务名称和服务对象的信息",
    moduleName)
export class serviceInfo {
    constructor(public serviceName?: string
        , public serviceObject?: pao.baseObject) {

    }
}
/**
 * 注册服务列表
 * @param serviceInfos 服务信息列表
 */
export function registerServices(serviceInfos: serviceInfo[]) {
    for (var serviceInfo of serviceInfos) {
        registerService(serviceInfo);
    }
}
/**
 * 注册服务
 * @param serviceInfo 服务信息
 */
export function registerService(serviceInfo: serviceInfo) {
    if (!globalServices[serviceInfo.serviceName]) {
        globalServices[serviceInfo.serviceName] = serviceInfo.serviceObject;
    }
}

/**
 * 请求
 * @param remoteRequest 远程请求
 * @returns 远程调用方法的结果
 */
export function request(request: pao.remoteRequest): any {
    let service = globalServices[request.serviceName];
    if (!service)
        throw new Error(`远程调用服务${request.serviceName}异常，服务找不到。`);

    let serviceFunc = service[request.functionName];
    if (!serviceFunc)
        throw new Error(`远程调用服务${request.serviceName}异常，方法${request.functionName}找不到。`);

    return serviceFunc.apply(this, request.args);
};

/**
 * 远程调用
 * @param req 请求
 * @param res 响应
 */
export function remoteCall(req: express.Request, res: express.Response) {
    // 定义了一个post变量，用于暂存请求体的信息
    let post = '';

    // 通过req的data事件监听函数，每当接受到请求体的数据，就累加到post变量中
    req.on('data', function (chunk) {
        post += chunk;
    });

    // 在end事件触发后，通过querystring.parse将post解析为真正的POST请求格式，然后向客户端返回。
    req.on('end', function () {
        let requestObj = pao.addonDeserialize(post);
        let result = request(requestObj);
        let response = pao.addonSerialize({
            d: result
        });
        res.send(response);
    });
};
/**
 * 主应用程序
 */
export let mainApplication : serverApplication;
/**
 * 服务应用
 */
@pao.addon("服务应用设置", "包含各种资源的主服务应用实体对象", moduleName)
export class serverApplication extends pao.application {
    /**
     * 服务列表
     */
    servics: serviceInfo[];

    /**
     * 服务端口
     */
    port: number = 3000;

    constructor(port?: number, services?: serviceInfo[]) {
        super();
        this.port = port;
        this.servics = services;
    }

    start() : void{
        super.start();
        mainApplication = this;
        if (this.servics) {
            registerServices(this.servics);
        }
    }
}


/**
 * 保存
 * @param filePath 文件路径
 */
export function saveObject(filePath: string, obj: pao.baseObject) : void{
    let configString = pao.addonSerialize(obj);
    fs.writeFileSync(filePath, configString);

    pao.log(`配置文件:${filePath}保存完毕`);
}

/**
 * 读取
 * @param filePath 文件路径
 */
export function loadObject(filePath: string) : any {
    let buffer = fs.readFileSync(filePath);
    let obj = pao.addonDeserialize(buffer.toString());

    pao.log(`配置文件:${filePath}读取完毕`);
    
    return obj;
}

/**
 * 准备配置
 * @param defaultConfig 默认配置对象
 * @param configFile 配置文件
 * @param loadConfig 是否从配置文件加载
 * @param saveConfig 是否保存配置文件
 */
export function prepareConfig(defaultConfig: pao.baseObject, configFile: string, loadConfig: boolean = false, saveConfig: boolean = true): pao.baseObject {   
    let configObject: pao.baseObject;
    // 加载应用程序配置
    if(loadConfig) {
        configObject = loadObject(configFile);
    } else {
        configObject = defaultConfig;
        if(saveConfig) {
            saveObject(configFile, configObject);
        }
    }
    return configObject;
}

/**
 * 启动服务
 * @param app Express应用
 * @param serverApp 应用程序 
 * @param configFile 配置文件
 * @param saveConfig 是否保存配置
 */
export function startServer(app: express.Express, serverApp : serverApplication, beforeStart? : ()=>void) {
    serverApp.start();

    // 设置端口
    app.set('port', process.env.port || serverApp.port);

    // 注册远程调用服务
    app.post('/remoteCall', remoteCall);
    
    // 执行启动事件
    if(beforeStart) {
        beforeStart();
    }

    // 启动服务
    http.createServer(app).listen(app.get('port'), function () {
        pao.log('服务启动，监听端口：' + app.get('port'));
    });
}

@pao.addon("数据库日志记录器",
    "将信息记录到数据库的日志记录器",
    moduleName)
export class databaseLogger extends pao.baseLogger {
    /**
     * 记录信息
     * @param date 日期
     * @param message 消息 
     * @param infoType 消息类型，可选的值：error: 错误；warning：警告；information：信息
     */
    log(date: Date, message: string, infoType: "error" | "warning" | "information" = "information"): void {
        // TODO: 改成记录到数据库
        pao.logToConsole(date, message, infoType);
    }
}


@pao.addon("文件式日志记录器",
    "将信息记录到文件的日志记录器",
    moduleName)
export class fileLogger extends pao.baseLogger {
    /**
     * 记录信息
     * @param date 日期
     * @param message 消息 
     * @param infoType 消息类型，可选的值：error: 错误；warning：警告；information：信息
     */
    log(date: Date, message: string, infoType: "error" | "warning" | "information" = "information"): void {
        // TODO: 改成记录到文件
        pao.logToConsole(date, message, infoType);
    }
}